﻿#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//malloc free
//void* malloc(size_t size);
//void* free(void* ptr);

//int main() {
//	int* p = (int*)malloc(sizeof(int) * 10);
//	if (p == NULL) {
//		perror("malloc");
//		return 1;
//	}
//	int i = 0;
//	for (i = 0; i < 10; i++) {
//		*(p + i) = i +1;
//	}
//	for (i = 0; i < 10; i++) {
//		printf("%d ", *(p+i));
//	}
//	free(p);
//	p = NULL;
//		return 0;
//}


//calloc 和  realloc
//void* calloc(size_t num, size_t size);   //将开辟的空间全部初始化为0
//void* realloc(void* ptr, size_t size);

//int main() {
//	int* p = (int*)calloc(5, sizeof(int));
//	if (p == NULL) {
//		perror("calloc");
//		return 1;
//	}
//	for (int i = 0; i < 5; i++) {
//		printf("%d ", *(p + i));
//	}
//	free(p);
//	p = NULL;
//	return 0;
//}

//realloc的使用
//int main() {
//	int* p = (int*)malloc(20);
//	if (p != NULL) {
//		for (int i = 0; i < 5; i++) {
//			*(p + i) = i + 1;
//		}
//		for (int i = 0; i < 5; i++) {
//			printf("%d ", *(p + i));
//		}
//	}
//	else
//		return 1;
//	int* ptr = (int*)realloc(p, 40);
//	if (ptr != NULL) {
//		p = ptr;
//		for (int i = 5; i < 10; i++) {
//			*(p + i) = i + 1;
//		}
//		for (int i = 5; i < 10; i++) {
//			printf("%d ", *(p + i));
//		}
//	}
//	else
//		return 1;
//	return 0;
//}


//realloc可以等价于malloc进行使用
//int main() {
//	int* p = (int*)realloc(NULL, 20);//等价于malloc(20)
//	return 0;
//}


//常⻅的动态内存的错误
//1.对NULL指针的解引⽤操作
//int main()
//{
//	int* p = (int*)malloc(INT_MAX / 4);
//	*p = 20;//如果开辟空间失败，p的值是NULL，就会有问题
//	printf("%d", *p);
//	free(p);
//}

//2.对动态开辟空间的越界访问
//int main()
//{
//	int i = 0;
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (NULL == p)
//	{
//		exit(EXIT_FAILURE);
//	}
//	for (i = 0; i <= 10; i++)
//	{
//		*(p + i) = i;//当i是10的时候越界访问
//	}
//	free(p);
//}

//3.对⾮动态开辟内存使⽤free释放
//void test()
//{
//	int a = 10;
//	int* p = &a;
//	free(p);  //只有动态内存分配才能用free释放
//}

//int main() {
//	test();
//	return 0;
//}

//4.使⽤free释放⼀块动态开辟内存的⼀部分
//void test()
//{
//	int* p = (int*)malloc(100);
//	p++;
//	free(p);//p不再指向动态内存的起始位置
//}


//5.对同⼀块动态内存多次释放
//void test()
//{
//	int* p = (int*)malloc(100);
//	free(p);
//	free(p);//重复释放
//}

//6.动态开辟内存忘记释放（内存泄漏）
//void test()
//{
//	int* p = (int*)malloc(100);
//	if (NULL != p)
//	{
//		*p = 20;
//	}
//}
//int main()
//{
//	test();
//	while (1);  //程序不停止，内存永远不会被释放
//}

//动态内存经典笔试题分析
//void GetMemory(char* p)
//{
//	p = (char*)malloc(100);
//}
//void Test(void)
//{
//	char* str = NULL;
//	GetMemory(str);
//	strcpy(str, "hello world");
//	printf(str);
//}
//
//int main() {
//	Test();  //调用GetMemory函数实际上传的是str的值，后续改的是p的值，str依然是空指针。对空指针进行操作会报错
//	return 0;
//}


//char* GetMemory(void)
//{
//	char p[] = "hello world";
//	return p;    //返回p的地址，但是p已被释放。
//}
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();   //str指向的空间已被释放，非法访问
//	printf(str);
//}
//
//int main() {
//	Test();    
//	return 0;
//}


//void GetMemory(char** p, int num)
//{
//	*p = (char*)malloc(num);
//}
//void Test(void)
//{
//	char* str = NULL;
//	GetMemory(&str, 100);
//	strcpy(str, "hello");
//	printf(str);  //没有释放动态内存开辟的空间
//	free(str);
//	str = NULL;
//}
//
//int main() {
//	Test();
//	return 0;
//}


//void Test(void)
//{
//	char* str = (char*)malloc(100);
//	strcpy(str, "hello");
//	free(str);  //str是野指针
//	if (str != NULL)
//	{
//		strcpy(str, "world");  //非法访问
//		printf(str);
//	}
//}
//
//int main() {
//	Test();
//	return 0;
//}



//柔性数组
struct S1 {
	int a;
	int b[];
};

int main() {
	struct S1* s = (struct S1*)malloc(sizeof(struct S1) + 40);
	if (s == NULL) {
		perror("malloc");
		return 1;
	}
	s->a = 20;
	for (int i = 0; i < 10; i++) {
		s->b[i] = i + 1;
	}
	for (int i = 0; i < 10; i++) {
		printf("%d ", s->b[i]);
	}
	struct S1* s2 = (struct S1*)realloc(s, sizeof(struct S1) + 80);
	if (s2 == NULL) {
		perror("realloc");
		return 1;
	}
	else {
		s = s2;
		for (int i = 10; i < 20; i++) {
			s->b[i] = i + 1;
		}
		for (int i = 0; i < 20; i++) {
			printf("%d ", s->b[i]);
		}
	}
		free(s);
		s = NULL;
		return 0;
	}





